/** create by liuhua at 2018年7月4日 下午4:58:54 **/
package com.star.truffle.module.user.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Service;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import com.star.truffle.core.KeyValue;
import com.star.truffle.core.annotation.IgnoreSecurity;
import com.star.truffle.core.security.StarFilterInvocationSecurityMetadataSource;
import com.star.truffle.core.security.dto.StarSecurityConfig;
import com.star.truffle.module.user.dto.RoleResourceRelationDto;

@Service("starFilterInvocationSecurityMetadataSource")
public class SourceMap extends StarFilterInvocationSecurityMetadataSource {

  @Autowired
  private RequestMappingHandlerMapping requestMappingHandlerMapping;
  @Autowired
  private ResourceService resourceService;
  
  @PostConstruct
  public void initResourceMap() {
    Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();
    Map<RequestMatcher, StarSecurityConfig> map = handlerMethodMap.entrySet().stream().filter(entry -> Stream.of(entry.getValue().getMethod().getDeclaredAnnotations()).anyMatch(annotation -> annotation.annotationType() == IgnoreSecurity.class))
    .flatMap(entry -> {
      RequestMappingInfo info = entry.getKey();
      Set<String> uris = info.getPatternsCondition().getPatterns();
      return uris.stream().map(uri -> KeyValue.<RequestMatcher, StarSecurityConfig>builder().key(new AntPathRequestMatcher(uri)).value(StarSecurityConfig.builder().ignore(true).build()).build());
    }).collect(HashMap::new, (m, v) -> m.put(v.getKey(), v.getValue()), HashMap::putAll);
    System.out.println(map.size());
    resourceMap = Collections.synchronizedMap(new HashMap<>());
    List<RoleResourceRelationDto> all = resourceService.queryAllRoleResource();
    if (null != all && !all.isEmpty()) {
      all.stream().filter(source -> StringUtils.isNotBlank(source.getUri()) && ! "menu".equals(source.getUri()) && StringUtils.isNotBlank(source.getRoleName()))
      .forEach(source -> {
        ConfigAttribute ca = new SecurityConfig("ROLE_" + source.getRoleName().toUpperCase());
        Stream.of(source.getUri().split(",")).filter(u -> StringUtils.isNotBlank(u)).forEach(u -> {
          RequestMatcher requestMatcher = new AntPathRequestMatcher(u);
          StarSecurityConfig value = resourceMap.get(requestMatcher);
          if (null == value) {
            value = new StarSecurityConfig();
            value.setAttributes(new ArrayList<>());
            resourceMap.put(requestMatcher, value);
          }
          value.getAttributes().add(ca);
        });
      });
    }
    System.out.println("前 -> " + resourceMap.size());
    resourceMap.putAll(map);
    System.out.println("后 -> " + resourceMap.size());
  }

}
